The Django backend defaults to local filesystem storage (Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Fer-2202/Proyecto_Final/llms.txt
Use this file to discover all available pages before exploring further.
media/). Supabase Storage is the recommended cloud replacement for production, providing a global CDN, Row Level Security (RLS), and a REST API compatible with Django’s Storage interface.
What uses storage
The following Django model fields write files to storage:| Model | Field | Upload path | Visibility |
|---|---|---|---|
UserProfile | profile_picture | profile_pics/ | Private |
Species | img | species/ | Public |
ExhibicionImage | image | exhibitions/ | Public |
PurchaseOrders | qr_image | qr_codes/ | Public |
Documents | document | documentos/ | Private |
ServiciosEducativos | image | servicios-educativos/ | Public |
ProgramaEducativo | image | programas/ | Public |
Environment variables
.env (backend)
Installing dependencies
Django settings
Hybrid storage (recommended)
Use local storage in development and Supabase in production:config/settings.py
django-storage-supabase (alternative)
Thedjango-storage-supabase package provides a drop-in DEFAULT_FILE_STORAGE backend:
config/settings.py
django-storage-supabase is currently in alpha. For production use, the custom SupabaseStorage class at config/supabase_storage.py is more reliable.Custom SupabaseStorage class
The backend includes a hand-rolledSupabaseStorage class that implements the full Django Storage interface:
config/supabase_storage.py
Creating buckets
Create the required buckets
Create the following buckets. Mark public buckets as Public so files are accessible without a signed URL:
| Bucket name | Access |
|---|---|
user-profiles | Private |
species | Public |
exhibitions | Public |
qr-codes | Public |
documents | Private |
educational-services | Public |
educational-programs | Public |
Apply RLS policies
Set Row Level Security policies (see Security policies below).
Uploading and retrieving files
Automatic — via Django models
No code changes are required in the models. OnceDEFAULT_FILE_STORAGE is set, all ImageField and FileField saves route through Supabase automatically:
models.py
Manual — using the storage class directly
Type-specific storage instances
Migrating existing local files
The management commandmigrate_to_supabase uploads all local media files and updates database references:
- Creates a local backup in
media_backup/ - Scans all models with file fields
- Uploads each file to Supabase, preserving directory structure
- Verifies each upload
- Updates the database reference to the new Supabase path
Security policies
Apply these RLS policies in the Supabase SQL editor (SQL Editor → New query):File validation
TheSupabaseStorage class validates uploads before sending them to Supabase:
- MIME type check — rejects files that do not match the expected content type
- Size limit — enforces a maximum file size per type
- Filename sanitisation — strips dangerous characters from file names
- Path traversal prevention — blocks
../sequences in upload paths
Debugging
Enable verbose storage logs insettings.py:
config/settings.py
Common errors
Invalid API key
Invalid API key
Verify that
SUPABASE_API_KEY in .env is correct. For private bucket operations you may need the service role key (SUPABASE_SERVICE_KEY) instead of the anon key.Bucket not found
Bucket not found
Check that the bucket name in
SUPABASE_STORAGE_BUCKET matches exactly what you created in the dashboard (case-sensitive).403 Forbidden when reading files
403 Forbidden when reading files
The bucket is set to private or an RLS policy is blocking access. Either make the bucket public or add a
SELECT policy for the relevant role.Migration is slow
Migration is slow
Use
--model to migrate one model at a time, or check your network connection. Large MEDIA_ROOT directories with thousands of files will take several minutes.